package generator.service;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import generator.config.GeneratorConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 代码生成服务类
 */
@Slf4j
@RequiredArgsConstructor
public class CodeGeneratorService {
    
    private final GeneratorConfig config;
    
    /**
     * 根据表名生成代码
     * @param tableNames 表名数组
     */
    public void generateCode(String[] tableNames) {
        try {
            // 生成所有代码（使用统一的生成方式）
            generateAllCodes(tableNames);
            
            // 如果需要生成额外的类，则生成VO、DTO和Pagination类
            if (config.getCode().isGenerateExtraClasses()) {
                for (String tableName : tableNames) {
                    generateExtraClasses(tableName);
                }
            }
            
            log.info("代码生成成功，表名: {}", String.join(",", tableNames));
        } catch (Exception e) {
            log.error("代码生成失败，表名: {}", String.join(",", tableNames), e);
            throw new RuntimeException("代码生成失败", e);
        }
    }
    
    /**
     * 生成所有代码
     */
    private void generateAllCodes(String[] tableNames) {
        // 创建自定义属性映射
        Map<String, Object> customMap = new HashMap<>();
        customMap.put("customAnnotations", config.getCode().isUseCustomEntityAnnotations());
        customMap.put("fullEntitySuperClass", config.getCode().getEntitySuperClass());
        
        FastAutoGenerator.create(
                config.getDatabase().getUrl(),
                config.getDatabase().getUsername(),
                config.getDatabase().getPassword())
                .globalConfig(builder -> {
                    builder.outputDir(config.getCode().getEntityOutputDir()) // 使用配置的输出目录
                            .author(config.getCode().getAuthor())
                            .disableOpenDir()
                            .enableSwagger()
                            .dateType(DateType.ONLY_DATE);
                })
                .packageConfig(builder -> {
                    builder.parent("") // 不使用父包
                            .entity(config.getCode().getPkg().getEntity()) // 空字符串
                            .mapper(config.getCode().getPkg().getMapper()) // 空字符串
                            .xml(config.getCode().getPkg().getXml()) // 空字符串
                            .service(config.getCode().getPkg().getService()) // 空字符串
                            .serviceImpl(config.getCode().getPkg().getServiceImpl()) // 空字符串
                            .controller(config.getCode().getPkg().getController()) // 空字符串
                            .pathInfo(Collections.singletonMap(com.baomidou.mybatisplus.generator.config.OutputFile.mapperXml, config.getCode().getXmlOutputDir()));
                })
                .templateConfig(builder -> {
                    // 如果使用自定义注解，则使用自定义模板
                    if (config.getCode().isUseCustomEntityAnnotations()) {
                        builder.entity("/templates/entity.java");
                    }
                })
                .injectionConfig(builder -> {
                    // 注入自定义属性
                    builder.customMap(customMap);
                })
                .strategyConfig(builder -> {
                    builder.addInclude(tableNames);
                    
                    // 实体类配置
                    builder.entityBuilder()
                            .enableLombok()
                            .enableTableFieldAnnotation()
                            .naming(NamingStrategy.underline_to_camel)
                            .columnNaming(NamingStrategy.underline_to_camel);
                    
                    // 添加实体类后缀支持
                    if (config.getCode().getEntitySuffix() != null && !config.getCode().getEntitySuffix().isEmpty()) {
                        builder.entityBuilder().formatFileName("%s" + config.getCode().getEntitySuffix());
                    }
                    
                    // 添加实体类继承支持
                    if (config.getCode().getEntitySuperClass() != null && !config.getCode().getEntitySuperClass().isEmpty()) {
                        builder.entityBuilder().superClass(config.getCode().getEntitySuperClass());
                    }
                    
                    // 添加忽略字段支持
                    if (config.getCode().getIgnoreFields() != null && !config.getCode().getIgnoreFields().isEmpty()) {
                        String[] ignoreFields = config.getCode().getIgnoreFields().split(",");
                        builder.entityBuilder().addSuperEntityColumns(ignoreFields);
                    }
                    
                    // 控制器配置
                    builder.controllerBuilder()
                            .enableRestStyle();
                    
                    // Service配置
                    builder.serviceBuilder()
                            .formatServiceFileName("%sService"); // 不添加I前缀
                    
                    // Mapper配置
                    builder.mapperBuilder()
                            .enableMapperAnnotation()
                            .enableBaseResultMap()
                            .enableBaseColumnList();
                })
                .templateEngine(new FreemarkerTemplateEngine())
                .execute();
    }
    
    /**
     * 生成额外的类（VO、DTO、Pagination）
     * @param tableName 表名
     */
    private void generateExtraClasses(String tableName) {
        // 将表名转换为驼峰命名
        String camelCaseName = underlineToCamelCase(tableName);
        
        // 创建子目录
        String subDirPath = config.getCode().getEntityOutputDir() + File.separator + camelCaseName;
        File subDir = new File(subDirPath);
        if (!subDir.exists()) {
            subDir.mkdirs();
        }
        
        // 生成VO类
        generateVOClass(subDirPath, camelCaseName);
        
        // 生成DTO类
        generateDTOClass(subDirPath, camelCaseName);
        
        // 生成Pagination类
        generatePaginationClass(subDirPath, camelCaseName);
    }
    
    /**
     * 生成VO类
     * @param dirPath 目录路径
     * @param className 类名
     */
    private void generateVOClass(String dirPath, String className) {
        String fileName = dirPath + File.separator + className + "VO.java";
        String content = generateClassContent(className + "VO");
        
        writeFile(fileName, content);
    }
    
    /**
     * 生成DTO类
     * @param dirPath 目录路径
     * @param className 类名
     */
    private void generateDTOClass(String dirPath, String className) {
        String fileName = dirPath + File.separator + className + "DTO.java";
        String content = generateClassContent(className + "DTO");
        
        writeFile(fileName, content);
    }
    
    /**
     * 生成Pagination类
     * @param dirPath 目录路径
     * @param className 类名
     */
    private void generatePaginationClass(String dirPath, String className) {
        String fileName = dirPath + File.separator + className + "Pagination.java";
        String content = generateClassContent(className + "Pagination");
        
        writeFile(fileName, content);
    }
    
    /**
     * 生成类内容
     * @param className 类名
     * @return 类内容
     */
    private String generateClassContent(String className) {
        StringBuilder content = new StringBuilder();
        content.append("import lombok.Data;\n\n");
        content.append("@Data\n");
        content.append("public class ").append(className).append(" {\n");
        content.append("    // TODO: 添加字段\n");
        content.append("}\n");
        return content.toString();
    }
    
    /**
     * 写入文件
     * @param fileName 文件名
     * @param content 文件内容
     */
    private void writeFile(String fileName, String content) {
        try (FileWriter writer = new FileWriter(fileName)) {
            writer.write(content);
            log.info("生成文件: {}", fileName);
        } catch (IOException e) {
            log.error("写入文件失败: {}", fileName, e);
        }
    }
    
    /**
     * 下划线转驼峰命名
     * @param underline 下划线命名
     * @return 驼峰命名
     */
    private String underlineToCamelCase(String underline) {
        if (underline == null || underline.isEmpty()) {
            return underline;
        }
        
        StringBuilder result = new StringBuilder();
        boolean nextUpperCase = false;
        
        for (int i = 0; i < underline.length(); i++) {
            char c = underline.charAt(i);
            
            if (c == '_') {
                nextUpperCase = true;
            } else {
                if (nextUpperCase) {
                    result.append(Character.toUpperCase(c));
                    nextUpperCase = false;
                } else {
                    // 第一个字符大写
                    if (i == 0) {
                        result.append(Character.toUpperCase(c));
                    } else {
                        result.append(c);
                    }
                }
            }
        }
        
        return result.toString();
    }
    
    /**
     * 生成实体类
     */
    private void generateEntities(String[] tableNames) {
        // 已合并到 generateAllCodes 方法中，避免重复生成
    }
    
    /**
     * 生成Mapper接口
     */
    private void generateMappers(String[] tableNames) {
        // 已合并到 generateAllCodes 方法中，避免重复生成
    }
    
    /**
     * 生成Service接口
     */
    private void generateServices(String[] tableNames) {
        // 已合并到 generateAllCodes 方法中，避免重复生成
    }
    
    /**
     * 生成Service实现类
     */
    private void generateServiceImpls(String[] tableNames) {
        // 已合并到 generateAllCodes 方法中，避免重复生成
    }
    
    /**
     * 生成Controller
     */
    private void generateControllers(String[] tableNames) {
        // 已合并到 generateAllCodes 方法中，避免重复生成
    }
}